// -*- swift -*-
// RUN: rm -rf %t ; mkdir -p %t
// RUN: %S/../../utils/gyb %s -o %t/CastTraps.swift
// RUN: %S/../../utils/line-directive %t/CastTraps.swift -- %target-build-swift %t/CastTraps.swift -o %t/a.out
// RUN: %S/../../utils/line-directive %t/CastTraps.swift -- %target-run %t/a.out
// REQUIRES: executable_test

// FIXME: Casting.cpp has dozens of places to fail a cast. This test does not 
// attempt to enumerate them all.

// XFAIL: linux

import StdlibUnittest
import Foundation


% types = []
% objectTypes = []
% protocolTypes = []

% types.append(['a.Class1', 'a.Class2'])
% objectTypes.append(['a.Class1', 'a.Class2'])
class Class1 { }
class Class2 { }

% types.append(['a.Struct1', 'a.Struct2'])
struct Struct1 { }
struct Struct2 { }

% types.append(['a.ObjCClass1', 'a.ObjCClass2'])
% objectTypes.append(['a.ObjCClass1', 'a.ObjCClass2'])
class ObjCClass1 : NSObject { }
class ObjCClass2 : NSObject { }

% types.append(['NSDateFormatter', 'NSNumberFormatter'])
% objectTypes.append(['NSDateFormatter', 'NSNumberFormatter'])
// non-Swift Objective-C class

% protocolTypes.append('a.Proto1')
% protocolTypes.append('a.Proto2')
protocol Proto1 { }
protocol Proto2 { }
% protocolTypes.append('NSURLSessionDelegate')
// non-Swift Objective-C protocol


var CastTrapsTestSuite = TestSuite("CastTraps")

// Test `(T1() as Any) as T2` cast failure 
// for all type pairs.

% for (t1, _) in types:
%   for (_, t2) in types:

CastTrapsTestSuite.test("${t1}__${t2}")
  .skip(.Custom(
    { _isFastAssertConfiguration() },
    reason: "this trap is not guaranteed to happen in -Ounchecked"))
  .crashOutputMatches("Could not cast value of type '${t1}' ")
  .crashOutputMatches(" to '${t2}'")
  .code
{
  let o = ${t1}() as Any
  expectCrashLater()
  o as! ${t2}
}

%   end
% end

// Test `(T1() as AnyObject) as T2` cast failure 
// for object type to protocol type pairs

% for (t1, _) in objectTypes:
%   for (t2) in protocolTypes:

CastTrapsTestSuite.test("${t1}__${t2}")
  .skip(.Custom(
    { _isFastAssertConfiguration() },
    reason: "this trap is not guaranteed to happen in -Ounchecked"))
  .crashOutputMatches("Could not cast value of type '${t1}' ")
  .crashOutputMatches(" to '${t2}'")
  .code
{
  let o = ${t1}() as AnyObject
  expectCrashLater()
  o as! ${t2}
}

%   end
% end

runAllTests()
